home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <netdb.h>
- #include "netconf.h"
- #include "../paths.h"
- #include "../xconf/xconf.h"
- #include "netconf.m"
-
- extern CONFIG_FILE f_conf_routes;
-
- /*
- Parse the argument of a route add command (read from ETC_CONF_ROUTES
- Return -1 if any error.
- */
- static int route_parsecmd (
- const char *buf,
- int noline,
- SSTRING &ip_dst,
- SSTRING &gateway,
- SSTRING &netmask,
- SSTRING &flags)
- {
- int ret = 0;
- char words[8][100];
- netmask.setfrom("");
- words[0][0] = words[1][0] = words[2][0] = words[3][0] = '\0';
- words[4][0] = words[5][0] = words[6][0] = words[7][0] = '\0';
- sscanf (buf,"%s %s %s %s %s %s %s %s"
- ,words[0],words[1],words[2],words[3]
- ,words[4],words[5],words[6],words[7]);
- int i=0;
- int seen_host = 0;
- if (strcmp(words[0],"-net")==0){
- flags.setfrom ("UG");
- i++;
- }else if (strcmp(words[0],"-host")==0){
- flags.setfrom ("UGH");
- seen_host = 1;
- i++;
- }else{
- flags.setfrom ("UG");
- }
- if (strcmp(words[i],"default")==0
- || device_validip(words[i],seen_host)){
- ip_dst.setfrom (words[i]);
- }else{
- struct netent *ent = getnetbyname (words[i]);
- if (ent == NULL){
- xconf_error (MSG_U(E_IVLDEST
- ,"Invalid destination %s for line %d in file %s\n%s\n")
- ,words[i],noline,ETC_CONF_ROUTES,buf);
- ret = -1;
- }else{
- devices_ip2a(ent,ip_dst);
- }
- }
- i++;
- if (strcmp(words[i],"gw")!=0){
- xconf_error (MSG_U(E_NOKEYGW
- ,"Keyword gw missing from line %d of file %s\n%s")
- ,noline,ETC_CONF_ROUTES,buf);
- ret = -1;
- }else{
- i++;
- if (device_validip(words[i],1)){
- gateway.setfrom (words[i]);
- }else{
- struct hostent *ent = gethostbyname (words[i]);
- if (ent == NULL){
- xconf_error (MSG_U(E_IVLGTW
- ,"Invalid gateway %s for line %d in file %s\n%s\n")
- ,words[i],noline,ETC_CONF_ROUTES,buf);
- ret = -1;
- }else{
- devices_ip2a (ent,gateway);
- }
- }
- i++;
- }
- if (words[i][0] != '\0'){
- if (strcmp(words[i],"netmask")!=0){
- xconf_error (MSG_U(E_NETMASK
- ,"Keyword netmask expected, on line %d of file %s\n%s")
- ,noline,ETC_CONF_ROUTES,buf);
- ret = -1;
- }else{
- i++;
- netmask.setfrom (words[i]);
- }
- }
- return ret;
- }
-
- /*
- Reformat a command (reverse route_parsecmd)
- */
- static void route_formatcmd(
- const SSTRING &ip_dst,
- const SSTRING &gateway,
- const SSTRING &netmask,
- const SSTRING &flags,
- char *buf)
- {
- buf[0] = '\0';
- if (flags.cmp("UG")==0){
- strcat (buf,"-net ");
- }else{
- strcat (buf,"-host ");
- }
- buf += strlen(buf);
- buf += sprintf(buf,"%s gw %s",ip_dst.get(),gateway.get());
- if (!netmask.is_empty()){
- sprintf (buf," netmask %s",netmask.get());
- }
- }
-
- /*
- Control a route in the kernel
- */
- PUBLIC ROUTE::ROUTE (
- const char *dst,
- const char *gate,
- const char *mask,
- const char *_flags,
- const char *_iface)
- {
- ip_dst.setfrom (dst);
- ip_gateway.setfrom (gate);
- netmask.setfrom (mask);
- flags.setfrom (_flags);
- iface.setfrom (_iface);
- tag = 0;
- }
- PUBLIC ROUTE::ROUTE (
- const char *buf,
- int noline) // Help generate error message
- {
- if (route_parsecmd(buf,noline,ip_dst,ip_gateway,netmask,flags)==-1){
- invalid_line.setfrom (buf);
- }
- tag = 0;
- }
- PUBLIC ROUTE::ROUTE ()
- {
- tag = 0;
- }
-
- PUBLIC ROUTE::~ROUTE ()
- {
- }
- /*
- Format and output in a file like ETC_CONF_ROUTE
- Output a line only if it contain either a valid info or an
- invalid (unparsable) line. So it does not generate empty line.
- */
- PUBLIC void ROUTE::write (FILE *fout)
- {
- if (!invalid_line.is_empty()){
- fprintf (fout,"%s\n",invalid_line.get());
- }else if (!ip_dst.is_empty()){
- char buf[300];
- route_formatcmd (ip_dst,ip_gateway,netmask,flags,buf);
- fprintf (fout,"%s\n",buf);
- }
- }
- /*
- Return a flag recorded by settag. This allows an application
- to mark a ROUTE as seen or ok or not ok and later, get the
- flag back. THis flag has no internal use for ROUTE. It is just
- kind enough to store it.
- */
- PUBLIC int ROUTE::gettag ()
- {
- return tag;
- }
- PUBLIC void ROUTE::settag (int _tag)
- {
- tag = _tag;
- }
- /*
- Return != 0 if this route is simply the route to the localnet
- without any gateway.
- */
- PUBLIC int ROUTE::isdevice ()
- {
- return ip_gateway.cmp("*")==0;
- }
- /*
- Get the interface (eth0) used for a route
- */
- PUBLIC const char *ROUTE::getiface ()
- {
- return iface.get();
- }
- /*
- Return the gateway of a route.
- */
- PUBLIC const char *ROUTE::getgateway()
- {
- return isdevice() ? iface.get() : ip_gateway.get();
- }
- /*
- Return the destination of a route.
- */
- PUBLIC const char *ROUTE::getdst()
- {
- return ip_dst.get();
- }
- /*
- Return if the destination is a host or a network.
- Return != 0 if it is a host.
- */
- PUBLIC int ROUTE::dst_is_host()
- {
- return flags.strchr('H')!=NULL;
- }
- /*
- Tell is a route match a destination.
- Return != 0 if true.
- */
- PUBLIC int ROUTE::match(const SSTRING &dst)
- {
- return ip_dst.cmp(dst)==0;
- }
- /*
- Tell if two routes are the same.
- Return 0 if different destination.
- 1 if same destination but different configuration.
- 2 if exactly the same.
- */
- PUBLIC int ROUTE::compare(
- const SSTRING &dst,
- const SSTRING &gateway,
- const SSTRING &o_netmask, // may be an empty string, in this
- // case it match anything
- const SSTRING &o_flags)
- {
- int ret = 0;
- if (ip_dst.cmp(dst) == 0){
- ret = 1;
- if (ip_gateway.cmp(gateway)==0
- && (o_netmask.is_empty() || netmask.cmp(o_netmask)==0)
- && flags.cmp(o_flags)==0){
- ret = 2;
- }
- }
- return ret;
- }
-
- /*
- Delete a route from the kernel routing table.
- Returne -1 if any error.
- */
- PUBLIC int ROUTE::kill ()
- {
- char cmd[100];
- sprintf (cmd,"del %s",ip_dst.get());
- return netconf_system_if ("route",cmd);
- }
-
- /*
- Indicate if a route define the loopback device
- */
- PUBLIC int ROUTE::is_loopback()
- {
- return ip_dst.cmp("127.0.0.1")==0 && ip_gateway.cmp("*")==0;
- }
- /*
- Indicate if a route define the default route
- */
- PUBLIC int ROUTE::is_default()
- {
- return ip_dst.cmp("default")==0;
- }
-
- /*
- read all the routes currently active
- */
- PUBLIC int ROUTES::readactive ()
- {
- FILE *fin = popen ("/sbin/route -n","r");
- int ret = -1;
- if (fin == NULL){
- xconf_error (MSG_U(E_CANTXROUTE
- ,"Can't execute command /sbin/route\n"
- "No way to update the route table\n"));
- }else{
- char buf[300];
- /* #Specification: route / /sbin/route
- netconf use /sbin/route -n to read the route table.
- It read only the first four fields (destination, gateway
- genmask and Flags) are read. The genmask is ignored
- */
- // Skip the first 2 lines
- fgets(buf,sizeof(buf)-1,fin);
- fgets(buf,sizeof(buf)-1,fin);
- while (fgets(buf,sizeof(buf)-1,fin)!=NULL){
- char ip_dst[20],ip_gate[20],gen_mask[20],flags[20];
- char junk[20],iface[20];
- if (sscanf (buf,"%s %s %s %s %s %s %s %s",ip_dst,ip_gate
- ,gen_mask,flags,junk,junk,junk,iface)!=8){
- xconf_error (MSG_U(E_IVLOUTPUT
- ,"Invalid output from /sbin/route\n%s\n")
- ,buf);
- }else{
- ROUTE *rt = new ROUTE (ip_dst,ip_gate,gen_mask,flags,iface);
- if (rt != NULL) add (rt);
- }
- }
- pclose (fin);
- }
- return ret;
- }
- PUBLIC void ROUTES::write (FILE *fout)
- {
- for (int i=0; i<getnb(); i++) getitem(i)->write (fout);
- }
- /*
- Get one ROUTE of the table or NULL
- */
- PUBLIC ROUTE *ROUTES::getitem(int no) const
- {
- return (ROUTE*)ARRAY::getitem(no);
- }
- /*
- Locate a ROUTE in the routing table.
- Return NULL if it does not exist.
- */
- PUBLIC ROUTE *ROUTES::find (const SSTRING &ip_dst)
- {
- ROUTE *ret = NULL;
- int nb = getnb();
- for (int i=0; i<nb; i++){
- ROUTE *pt = getitem(i);
- if (pt->match(ip_dst)){
- ret = pt;
- break;
- }
- }
- return ret;
- }
-
- extern NETCONF_HELP_FILE help_routes;
- static CONFIG_FILE f_var_run_current (VAR_RUN_ROUTES_CURRENT
- ,help_routes,CONFIGF_MANAGED|CONFIGF_OPTIONNAL|CONFIGF_ERASED);
- /*
- Read all route info stored in VAR_RUN_ROUTES_CURRENT
- */
- PUBLIC void ROUTES::readbyme()
- {
- FILE *fin = f_var_run_current.fopen("r");
- if (fin != NULL){
- char buf[400];
- int noline = 0;
- while (fgets(buf,sizeof(buf)-1,fin)){
- noline++;
- add (new ROUTE (buf,0));
- }
- fclose (fin);
- }
- }
- /*
- Store all route set during this session in VAR_RUN_ROUTES_CURRENT
- */
- PUBLIC void ROUTES::writebyme()
- {
- FILE *fout = f_var_run_current.fopen("w");
- if (fout != NULL){
- write (fout);
- fclose (fout);
- }
- }
-
- /*
- Read the /etc/conf.routes and install/correct all routes.
- New routes are added, current routes are validated and corrected
- if need (deleted, reinstall), and obsolete route are removed.
-
- Return -1 if any error.
- */
- int route_install ()
- {
- int ret = -1;
- /* #Specification: ETC_CONF_ROUTES / optionnal
- The file ETC_CONF_ROUTES is optionnal. It means no extra
- routes (only route to local network) will be set if missing.
- */
- ROUTES active;
- active.readactive();
- ROUTES lasttime; // List of routes established by this program
- // during a different session
- lasttime.readbyme();
- ROUTES thistime; // Routes that will be set or accepted this
- // time
- FILE *fin = f_conf_routes.fopen ("r");
- if (fin != NULL){
- char buf[300];
- int noline;
- while (fgets_strip (buf,sizeof(buf)-1,fin,&noline)!=NULL){
- /* #Specification: ETC_CONF_ROUTES / format
- The format of /etc/conf.routes is simply the end
- of a route command (everything after the add keyword).
-
- So if you want to install a default route (and want
- to do so by editing /etc/conf.routes manually, then you
- write
-
- -net default gw router
-
- You only write routes which are not associated to devices.
- The primary route to the ethernet network is taken
- care automaticly by netconf. You just place extra routes
- here.
- */
- SSTRING ip_dst,gateway,netmask,flags;
- if(route_parsecmd (buf,noline,ip_dst,gateway
- ,netmask,flags) != -1){
- ROUTE * rt = active.find (ip_dst);
- int add = 0;
- if (rt == NULL){
- add = 1;
- }else if(lasttime.find(ip_dst)!=NULL){
- // This route was set by me, check if it has
- // to be updated
- rt->settag(1);
- if (rt->compare (ip_dst,gateway,netmask,flags) != 2){
- rt->kill();
- add = 1;
- }else{
- // This route is still valid, must be written
- // back into /var/run/routes.current
- thistime.add (new ROUTE (buf,0));
- }
- }
- /* #Specification: netconf / update routes
- netconf will only update a route or delete it if
- it is not needed any more or is slightly different.
- This means that you should not see any network
- problem if you add a new route and run netconf --update
- */
- if (add){
- char cmd[300];
- sprintf (cmd,"add %s",buf);
- ret = netconf_system_if ("route",cmd);
- thistime.add (new ROUTE (buf,0));
- }
- }
- }
- fclose (fin);
- }
- /* #Specification: netconf / update routes / routed
- netconf kills any route not found any more in ETC_CONF_ROUTES
- This may cause a problem to routed. To avoid it, netconf
- will only kill the routes it have setup itself.
-
- Comments welcome.
- */
- for (int i=0; i<active.getnb(); i++){
- ROUTE *pt = active.getitem(i);
- if (pt->gettag()==0
- && lasttime.find(pt->getdst())!=NULL
- && !pt->isdevice()) pt->kill();
- }
- if (!simul_ison())thistime.writebyme();
- return ret;
- }
- /*
- Check if a route is active to a destination
- */
- int route_isactive (
- const char *dest,
- char *gateway)
- {
- ROUTES active;
- active.readactive();
- ROUTE *rt = active.find(dest);
- if (rt != NULL) strcpy (gateway,rt->getgateway());
- return rt != NULL;
- }
-
-